home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Tools / Win95 Secrets / SETUP.Z / EXEDUMP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-19  |  19.3 KB  |  588 lines

  1. //==================================
  2. // PEDUMP - Matt Pietrek 1995
  3. // FILE: EXEDUMP.C
  4. //==================================
  5.  
  6. #include <windows.h>
  7. #include <stdio.h>
  8. #pragma hdrstop
  9. #include "common.h"
  10. #include "extrnvar.h"
  11.  
  12. void DumpExeDebugDirectory(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  13. {
  14.     PIMAGE_DEBUG_DIRECTORY debugDir;
  15.     PIMAGE_SECTION_HEADER header;
  16.     DWORD offsetInto_rdata;
  17.     DWORD va_debug_dir;
  18.     DWORD size;
  19.     
  20.     // This line was so long that we had to break it up
  21.     va_debug_dir = pNTHeader->OptionalHeader.
  22.                         DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].
  23.                         VirtualAddress;
  24.     if ( va_debug_dir == 0 )
  25.         return;
  26.  
  27.     // If we found a .debug section, and the debug directory is at the
  28.     // beginning of this section, it looks like a Borland file
  29.     header = GetSectionHeader(".debug", pNTHeader);
  30.     if ( header && (header->VirtualAddress == va_debug_dir) )
  31.     {
  32.         debugDir = (PIMAGE_DEBUG_DIRECTORY)(header->PointerToRawData+base);
  33.         size = pNTHeader->OptionalHeader.
  34.                 DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size *
  35.                 sizeof(IMAGE_DEBUG_DIRECTORY);
  36.     }
  37.     else    // Look for microsoft debug directory in the .rdata section
  38.     {
  39.         header = GetSectionHeader(".rdata", pNTHeader);
  40.         if ( !header )
  41.             return;
  42.  
  43.         size = pNTHeader->OptionalHeader.
  44.                         DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
  45.     
  46.         offsetInto_rdata = va_debug_dir - header->VirtualAddress;
  47.         debugDir = MakePtr(PIMAGE_DEBUG_DIRECTORY, base,
  48.                             header->PointerToRawData + offsetInto_rdata);
  49.     }
  50.  
  51.     DumpDebugDirectory( debugDir, size, base );
  52. }
  53.  
  54. // Function prototype (necessary because two functions recurse)
  55. void DumpResourceDirectory
  56. (
  57.     PIMAGE_RESOURCE_DIRECTORY resDir, DWORD resourceBase,
  58.     DWORD level, DWORD resourceType
  59. );
  60.  
  61. // The predefined resource types
  62. char *SzResourceTypes[] = {
  63. "???_0", "CURSOR", "BITMAP", "ICON", "MENU", "DIALOG", "STRING", "FONTDIR",
  64. "FONT", "ACCELERATORS", "RCDATA", "MESSAGETABLE", "GROUP_CURSOR",
  65. "???_13", "GROUP_ICON", "???_15", "VERSION"
  66. };
  67.  
  68. // Get an ASCII string representing a resource type
  69. void GetResourceTypeName(DWORD type, PSTR buffer, UINT cBytes)
  70. {
  71.     if ( type <= 16 )
  72.         strncpy(buffer, SzResourceTypes[type], cBytes);
  73.     else
  74.         sprintf(buffer, "%X", type);
  75. }
  76.  
  77. //
  78. // If a resource entry has a string name (rather than an ID), go find
  79. // the string and convert it from unicode to ascii.
  80. //
  81. void GetResourceNameFromId
  82. (
  83.     DWORD id, DWORD resourceBase, PSTR buffer, UINT cBytes
  84. )
  85. {
  86.     PIMAGE_RESOURCE_DIR_STRING_U prdsu;
  87.  
  88.     // If it's a regular ID, just format it.
  89.     if ( !(id & IMAGE_RESOURCE_NAME_IS_STRING) )
  90.     {
  91.         sprintf(buffer, "%X", id);
  92.         return;
  93.     }
  94.     
  95.     id &= 0x7FFFFFFF;
  96.     prdsu = (PIMAGE_RESOURCE_DIR_STRING_U)(resourceBase + id);
  97.  
  98.     // prdsu->Length is the number of unicode characters
  99.     WideCharToMultiByte(CP_ACP, 0, prdsu->NameString, prdsu->Length,
  100.                         buffer, cBytes, 0, 0);
  101.     buffer[ min(cBytes-1,prdsu->Length) ] = 0;  // Null terminate it!!!
  102. }
  103.  
  104. //
  105. // Dump the information about one resource directory entry.  If the
  106. // entry is for a subdirectory, call the directory dumping routine
  107. // instead of printing information in this routine.
  108. //
  109. void DumpResourceEntry
  110. (
  111.     PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry,
  112.     DWORD resourceBase,
  113.     DWORD level
  114. )
  115. {
  116.     UINT i;
  117.     char nameBuffer[128];
  118.     PIMAGE_RESOURCE_DATA_ENTRY pResDataEntry;
  119.     
  120.     if ( resDirEntry->OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY )
  121.     {
  122.         DumpResourceDirectory( (PIMAGE_RESOURCE_DIRECTORY)
  123.             ((resDirEntry->OffsetToData & 0x7FFFFFFF) + resourceBase),
  124.             resourceBase, level, resDirEntry->Name);
  125.         return;
  126.     }
  127.  
  128.     // Spit out the spacing for the level indentation
  129.     for ( i=0; i < level; i++ )
  130.         printf("    ");
  131.  
  132.     if ( resDirEntry->Name & IMAGE_RESOURCE_NAME_IS_STRING )
  133.     {
  134.         GetResourceNameFromId(resDirEntry->Name, resourceBase, nameBuffer,
  135.                               sizeof(nameBuffer));
  136.         printf("Name: %s  DataEntryOffs: %08X\n",
  137.             nameBuffer, resDirEntry->OffsetToData);
  138.     }
  139.     else
  140.     {
  141.         printf("ID: %08X  DataEntryOffs: %08X\n",
  142.                 resDirEntry->Name, resDirEntry->OffsetToData);
  143.     }
  144.     
  145.     // the resDirEntry->OffsetToData is a pointer to an
  146.     // IMAGE_RESOURCE_DATA_ENTRY.  Go dump out that information.  First,
  147.     // spit out the proper indentation
  148.     for ( i=0; i < level; i++ )
  149.         printf("    ");
  150.     
  151.     pResDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)
  152.                     (resourceBase + resDirEntry->OffsetToData);
  153.     printf("Offset: %05X  Size: %05X  CodePage: %X\n",
  154.             pResDataEntry->OffsetToData, pResDataEntry->Size,
  155.             pResDataEntry->CodePage);
  156. }
  157.  
  158. //
  159. // Dump the information about one resource directory.
  160. //
  161. void DumpResourceDirectory
  162. (
  163.     PIMAGE_RESOURCE_DIRECTORY resDir,
  164.     DWORD resourceBase,
  165.     DWORD level,
  166.     DWORD resourceType
  167. )
  168. {
  169.     PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry;
  170.     char szType[64];
  171.     UINT i;
  172.  
  173.     // Spit out the spacing for the level indentation
  174.     for ( i=0; i < level; i++ )
  175.         printf("    ");
  176.  
  177.     // Level 1 resources are the resource types
  178.     if ( level == 1 && !(resourceType & IMAGE_RESOURCE_NAME_IS_STRING) )
  179.     {
  180.         GetResourceTypeName( resourceType, szType, sizeof(szType) );
  181.     }
  182.     else    // Just print out the regular id or name
  183.     {
  184.         GetResourceNameFromId( resourceType, resourceBase, szType,
  185.                                sizeof(szType) );
  186.     }
  187.     
  188.     printf(
  189.         "ResDir (%s) Named:%02X ID:%02X TimeDate:%08X Vers:%u.%02u Char:%X\n",
  190.         szType, resDir->NumberOfNamedEntries, resDir->NumberOfIdEntries,
  191.         resDir->TimeDateStamp, resDir->MajorVersion,
  192.         resDir->MinorVersion,resDir->Characteristics);
  193.  
  194.     resDirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir+1);
  195.     
  196.     for ( i=0; i < resDir->NumberOfNamedEntries; i++, resDirEntry++ )
  197.         DumpResourceEntry(resDirEntry, resourceBase, level+1);
  198.  
  199.     for ( i=0; i < resDir->NumberOfIdEntries; i++, resDirEntry++ )
  200.         DumpResourceEntry(resDirEntry, resourceBase, level+1);
  201. }
  202.  
  203. //
  204. // Top level routine called to dump out the entire resource hierarchy
  205. //
  206. void DumpResourceSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  207. {
  208.     PIMAGE_RESOURCE_DIRECTORY resDir;
  209.     
  210.     resDir = GetSectionPtr(".rsrc", pNTHeader, (DWORD)base);
  211.     if ( !resDir )
  212.         return;
  213.     
  214.     printf("Resources\n");
  215.     DumpResourceDirectory(resDir, (DWORD)resDir, 0, 0);
  216. }
  217.  
  218. //
  219. // Dump the imports table (the .idata section) of a PE file
  220. //
  221. void DumpImportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  222. {
  223.     PIMAGE_IMPORT_DESCRIPTOR importDesc;
  224.     PIMAGE_SECTION_HEADER pSection;
  225.     PIMAGE_THUNK_DATA thunk, thunkIAT=0;
  226.     PIMAGE_IMPORT_BY_NAME pOrdinalName;
  227.     DWORD importsStartRVA;
  228.     INT delta = -1;
  229.  
  230.     // Look up where the imports section is (normally in the .idata section)
  231.     // but not necessarily so.  Therefore, grab the RVA from the data dir.
  232.     importsStartRVA = pNTHeader->OptionalHeader.DataDirectory
  233.                             [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  234.     if ( !importsStartRVA )
  235.         return;
  236.  
  237.     // Get the IMAGE_SECTION_HEADER that contains the imports.  This is
  238.     // usually the .idata section, but doesn't have to be.
  239.     pSection = GetEnclosingSectionHeader( importsStartRVA, pNTHeader );
  240.     if ( !pSection )
  241.         return;
  242.  
  243.     delta = (INT)(pSection->VirtualAddress-pSection->PointerToRawData);
  244.     
  245.     importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (importsStartRVA - delta + base);
  246.             
  247.     printf("Imports Table:\n");
  248.     
  249.     while ( 1 )
  250.     {
  251.         // See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR
  252.         if ( (importDesc->TimeDateStamp==0 ) && (importDesc->Name==0) )
  253.             break;
  254.         
  255.         printf("  %s\n", (PBYTE)(importDesc->Name) - delta + base);
  256.  
  257.         printf("  Hint/Name Table: %08X\n", importDesc->Characteristics);
  258.         printf("  TimeDateStamp:   %08X\n", importDesc->TimeDateStamp);
  259.         printf("  ForwarderChain:  %08X\n", importDesc->ForwarderChain);
  260.         printf("  First thunk RVA: %08X\n", importDesc->FirstThunk);
  261.     
  262.         thunk = (PIMAGE_THUNK_DATA)importDesc->Characteristics;
  263.         thunkIAT = (PIMAGE_THUNK_DATA)importDesc->FirstThunk;
  264.  
  265.         if ( thunk == 0 )   // No Characteristics field?
  266.         {
  267.             // Yes! Gotta have a non-zero FirstThunk field then.
  268.             thunk = thunkIAT;
  269.             
  270.             if ( thunk == 0 )   // No FirstThunk field?  Ooops!!!
  271.                 return;
  272.         }
  273.         
  274.         // Adjust the pointer to point where the tables are in the
  275.         // mem mapped file.
  276.         thunk = (PIMAGE_THUNK_DATA)( (PBYTE)thunk - delta + base);
  277.         thunkIAT = (PIMAGE_THUNK_DATA)( (PBYTE)thunkIAT - delta + base);
  278.     
  279.         printf("  Ordn  Name\n");
  280.         
  281.         while ( 1 ) // Loop forever (or until we break out)
  282.         {
  283.             if ( thunk->u1.AddressOfData == 0 )
  284.                 break;
  285.  
  286.             if ( thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG )
  287.             {
  288.                 printf( "  %4u", IMAGE_ORDINAL(thunk->u1.Ordinal) );
  289.             }
  290.             else
  291.             {
  292.                 pOrdinalName = thunk->u1.AddressOfData;
  293.                 pOrdinalName = (PIMAGE_IMPORT_BY_NAME)
  294.                                 ((PBYTE)pOrdinalName - delta + base);
  295.                     
  296.                 printf("  %4u  %s", pOrdinalName->Hint, pOrdinalName->Name);
  297.             }
  298.             
  299.  
  300.             if ( fShowIATentries )
  301.                 printf( " (IAT: %08X)", thunkIAT->u1.Function );
  302.  
  303.             printf( "\n" );
  304.  
  305.             thunk++;            // Advance to next thunk
  306.             thunkIAT++;         // advance to next thunk
  307.         }
  308.  
  309.         importDesc++;   // advance to next IMAGE_IMPORT_DESCRIPTOR
  310.         printf("\n");
  311.     }
  312. }
  313.  
  314. //
  315. // Dump the exports table (usually the .edata section) of a PE file
  316. //
  317. void DumpExportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  318. {
  319.     PIMAGE_EXPORT_DIRECTORY exportDir;
  320.     PIMAGE_SECTION_HEADER header;
  321.     INT delta; 
  322.     PSTR filename;
  323.     DWORD i;
  324.     PDWORD functions;
  325.     PWORD ordinals;
  326.     PSTR *name;
  327.     DWORD exportsStartRVA, exportsEndRVA;
  328.     
  329.     exportsStartRVA = pNTHeader->OptionalHeader.DataDirectory
  330.                             [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  331.     exportsEndRVA = exportsStartRVA + pNTHeader->OptionalHeader.DataDirectory
  332.                             [IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  333.  
  334.     // Get the IMAGE_SECTION_HEADER that contains the exports.  This is
  335.     // usually the .edata section, but doesn't have to be.
  336.     header = GetEnclosingSectionHeader( exportsStartRVA, pNTHeader );
  337.     if ( !header )
  338.         return;
  339.  
  340.     delta = (INT)(header->VirtualAddress - header->PointerToRawData);
  341.         
  342.     exportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, base,
  343.                          exportsStartRVA - delta);
  344.         
  345.     filename = (PSTR)(exportDir->Name - delta + base);
  346.         
  347.     printf("exports table:\n\n");
  348.     printf("  Name:            %s\n", filename);
  349.     printf("  Characteristics: %08X\n", exportDir->Characteristics);
  350.     printf("  TimeDateStamp:   %08X\n", exportDir->TimeDateStamp);
  351.     printf("  Version:         %u.%02u\n", exportDir->MajorVersion,
  352.             exportDir->MinorVersion);
  353.     printf("  Ordinal base:    %08X\n", exportDir->Base);
  354.     printf("  # of functions:  %08X\n", exportDir->NumberOfFunctions);
  355.     printf("  # of Names:      %08X\n", exportDir->NumberOfNames);
  356.     
  357.     functions = (PDWORD)((DWORD)exportDir->AddressOfFunctions - delta + base);
  358.     ordinals = (PWORD)((DWORD)exportDir->AddressOfNameOrdinals - delta + base);
  359.     name = (PSTR *)((DWORD)exportDir->AddressOfNames - delta + base);
  360.  
  361.     printf("\n  Entry Pt  Ordn  Name\n");
  362.     for ( i=0; i < exportDir->NumberOfFunctions; i++ )
  363.     {
  364.         DWORD entryPointRVA = functions[i];
  365.         DWORD j;
  366.  
  367.         if ( entryPointRVA == 0 )   // Skip over gaps in exported function
  368.             continue;               // ordinals (the entrypoint is 0 for
  369.                                     // these functions).
  370.  
  371.         printf("  %08X  %4u", entryPointRVA, i + exportDir->Base );
  372.  
  373.         // See if this function has an associated name exported for it.
  374.         for ( j=0; j < exportDir->NumberOfNames; j++ )
  375.             if ( ordinals[j] == i )
  376.                 printf("  %s", name[j] - delta + base);
  377.  
  378.         // Is it a forwarder?  If so, the entry point RVA is inside the
  379.         // .edata section, and is an RVA to the DllName.EntryPointName
  380.         if ( (entryPointRVA >= exportsStartRVA)
  381.              && (entryPointRVA <= exportsEndRVA) )
  382.         {
  383.             printf(" (forwarder -> %s)", entryPointRVA - delta + base );
  384.         }
  385.         
  386.         printf("\n");
  387.     }
  388. }
  389.  
  390. // The names of the available base relocations
  391. char *SzRelocTypes[] = {
  392. "ABSOLUTE","HIGH","LOW","HIGHLOW","HIGHADJ","MIPS_JMPADDR",
  393. "I860_BRADDR","I860_SPLIT" };
  394.  
  395. //
  396. // Dump the base relocation table of a PE file
  397. //
  398. void DumpBaseRelocationsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  399. {
  400.     PIMAGE_BASE_RELOCATION baseReloc;
  401.     
  402.     baseReloc = GetSectionPtr(".reloc", pNTHeader, base);
  403.     if ( !baseReloc )
  404.         return;
  405.  
  406.     printf("base relocations:\n\n");
  407.  
  408.     while ( baseReloc->SizeOfBlock != 0 )
  409.     {
  410.         unsigned i,cEntries;
  411.         PWORD pEntry;
  412.         char *szRelocType;
  413.         WORD relocType;
  414.         
  415.         cEntries = (baseReloc->SizeOfBlock-sizeof(*baseReloc))/sizeof(WORD);
  416.         pEntry = MakePtr( PWORD, baseReloc, sizeof(*baseReloc) );
  417.         
  418.         printf("Virtual Address: %08X  size: %08X\n",
  419.                 baseReloc->VirtualAddress, baseReloc->SizeOfBlock);
  420.             
  421.         for ( i=0; i < cEntries; i++ )
  422.         {
  423.             // Extract the top 4 bits of the relocation entry.  Turn those 4
  424.             // bits into an appropriate descriptive string (szRelocType)
  425.             relocType = (*pEntry & 0xF000) >> 12;
  426.             szRelocType = relocType < 8 ? SzRelocTypes[relocType] : "unknown";
  427.             
  428.             printf("  %08X %s\n",
  429.                     (*pEntry & 0x0FFF) + baseReloc->VirtualAddress,
  430.                     szRelocType);
  431.             pEntry++;   // Advance to next relocation entry
  432.         }
  433.         
  434.         baseReloc = MakePtr( PIMAGE_BASE_RELOCATION, baseReloc,
  435.                              baseReloc->SizeOfBlock);
  436.     }
  437. }
  438.  
  439. //
  440. // Dump out the new IMAGE_BOUND_IMPORT_DESCRIPTOR that NT 3.51 added
  441. //
  442. void DumpBoundImportDescriptors( DWORD base, PIMAGE_NT_HEADERS pNTHeader )
  443. {
  444.     DWORD bidRVA;   // Bound import descriptors RVA
  445.     PIMAGE_BOUND_IMPORT_DESCRIPTOR pibid;
  446.  
  447.     bidRVA = pNTHeader->OptionalHeader.DataDirectory
  448.                         [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress;
  449.     if ( !bidRVA )
  450.         return;
  451.     
  452.     pibid = MakePtr( PIMAGE_BOUND_IMPORT_DESCRIPTOR, base, bidRVA );
  453.     
  454.     printf( "Bound import descriptors:\n\n" );
  455.     printf( "  Module        TimeDate\n" );
  456.     printf( "  ------------  --------\n" );
  457.     
  458.     while ( pibid->TimeDateStamp )
  459.     {
  460.         unsigned i;
  461.         PIMAGE_BOUND_FORWARDER_REF pibfr;
  462.         
  463.         printf( "  %-12s  %08X\n", base + bidRVA + pibid->OffsetModuleName,
  464.                                   pibid->TimeDateStamp );
  465.                             
  466.         pibfr = MakePtr(PIMAGE_BOUND_FORWARDER_REF, pibid,
  467.                             sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR));
  468.  
  469.         for ( i=0; i < pibid->NumberOfModuleForwarderRefs; i++ )
  470.         {
  471.             printf("    forwarder:  %-12s  %08X\n", 
  472.                             base + bidRVA + pibfr->OffsetModuleName,
  473.                             pibfr->TimeDateStamp );
  474.             pibfr++;    // advance to next forwarder ref
  475.                 
  476.             // Keep the outer loop pointer up to date too!
  477.             pibid = MakePtr( PIMAGE_BOUND_IMPORT_DESCRIPTOR, pibid,
  478.                              sizeof( IMAGE_BOUND_FORWARDER_REF ) );
  479.         }
  480.  
  481.         pibid++;    // Advance to next pibid;
  482.     }
  483. }
  484.  
  485. //
  486. // top level routine called from PEDUMP.C to dump the components of a PE file
  487. //
  488. void DumpExeFile( PIMAGE_DOS_HEADER dosHeader )
  489. {
  490.     PIMAGE_NT_HEADERS pNTHeader;
  491.     DWORD base = (DWORD)dosHeader;
  492.     
  493.     pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader,
  494.                                 dosHeader->e_lfanew );
  495.  
  496.     // First, verify that the e_lfanew field gave us a reasonable
  497.     // pointer, then verify the PE signature.
  498.     __try
  499.     {
  500.         if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
  501.         {
  502.             printf("Not a Portable Executable (PE) EXE\n");
  503.             return;
  504.         }
  505.     }
  506.     __except( TRUE )    // Should only get here if pNTHeader (above) is bogus
  507.     {
  508.         printf( "invalid .EXE\n");
  509.         return;
  510.     }
  511.     
  512.     DumpHeader((PIMAGE_FILE_HEADER)&pNTHeader->FileHeader);
  513.     printf("\n");
  514.  
  515.     DumpOptionalHeader((PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader);
  516.     printf("\n");
  517.  
  518.     DumpSectionTable( IMAGE_FIRST_SECTION(pNTHeader), 
  519.                         pNTHeader->FileHeader.NumberOfSections, TRUE);
  520.     printf("\n");
  521.  
  522.     DumpExeDebugDirectory(base, pNTHeader);
  523.     if ( pNTHeader->FileHeader.PointerToSymbolTable == 0 )
  524.         PCOFFDebugInfo = 0; // Doesn't really exist!
  525.     printf("\n");
  526.  
  527.     DumpResourceSection(base, pNTHeader);
  528.     printf("\n");
  529.  
  530.     DumpImportsSection(base, pNTHeader);
  531.     printf("\n");
  532.     
  533.     if ( pNTHeader->OptionalHeader.DataDirectory
  534.                             [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
  535.                             .VirtualAddress )
  536.     {
  537.         DumpBoundImportDescriptors( base, pNTHeader );
  538.         printf( "\n" );
  539.     }
  540.     
  541.     DumpExportsSection(base, pNTHeader);
  542.     printf("\n");
  543.  
  544.     if ( fShowRelocations )
  545.     {
  546.         DumpBaseRelocationsSection(base, pNTHeader);
  547.         printf("\n");
  548.     } 
  549.  
  550.     //
  551.     // Initialize these vars here since we'll need them in DumpLineNumbers
  552.     //
  553.     PCOFFSymbolTable = MakePtr(PIMAGE_SYMBOL, base,
  554.                         pNTHeader->FileHeader.PointerToSymbolTable);
  555.     COFFSymbolCount = pNTHeader->FileHeader.NumberOfSymbols;
  556.  
  557.     if ( fShowSymbolTable && PCOFFDebugInfo )
  558.     {
  559.         DumpCOFFHeader( PCOFFDebugInfo );
  560.         printf("\n");
  561.     }
  562.     
  563.     if ( fShowLineNumbers && PCOFFDebugInfo )
  564.     {
  565.         DumpLineNumbers( MakePtr(PIMAGE_LINENUMBER, PCOFFDebugInfo,
  566.                             PCOFFDebugInfo->LvaToFirstLinenumber),
  567.                             PCOFFDebugInfo->NumberOfLinenumbers);
  568.         printf("\n");
  569.     }
  570.  
  571.     if ( fShowSymbolTable )
  572.     {
  573.         if ( pNTHeader->FileHeader.NumberOfSymbols 
  574.             && pNTHeader->FileHeader.PointerToSymbolTable)
  575.         {
  576.             DumpSymbolTable(PCOFFSymbolTable, COFFSymbolCount);
  577.             printf("\n");
  578.         }
  579.     }
  580.     
  581.     if ( fShowRawSectionData )
  582.     {
  583.         DumpRawSectionData( (PIMAGE_SECTION_HEADER)(pNTHeader+1),
  584.                             dosHeader,
  585.                             pNTHeader->FileHeader.NumberOfSections);
  586.     }
  587. }
  588.